package builtins

import (
	"context"

	"tvl.fyi/tvix/eval/value"
)

// baseBuiltin holds the private data for a given builtin (its
// function pointer, documentation and so on). This structure never
// changes between different invocations of a builtin, and is not
// directly a user-facing value.
type baseBuiltin struct {
	function func(ctx context.Context, args []value.NixValue) (value.NixValue, error)
	argcount int
	name     string
}

// NixBuiltin represents the Nix language value for a builtin
// function. It can either be unapplied, or partially applied.
type NixBuiltin struct {
	base     baseBuiltin
	partials []value.NixValue
}

func (NixBuiltin) NixType() string {
	return "lambda"
}

func (b NixBuiltin) String() string {
	if len(b.partials) == 0 {
		return "«primop»"
	} else {
		return "«primop-app»"
	}
}

func (NixBuiltin) Strict(context.Context) error {
	return nil
}

func (b NixBuiltin) Name() string {
	return b.base.name
}

func (b *NixBuiltin) Call(ctx context.Context, arg value.NixValue) (value.NixValue, error) {
	args := append(b.partials, arg)
	if len(args) == b.base.argcount {
		return b.base.function(ctx, args)
	}

	return NixBuiltin{
		base:     b.base,
		partials: args,
	}, nil
}
